/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       hero.h

	$Header: /game/hero.h $

	$NoKeywords: $

 ************************************************************************/

#ifndef HERO_H_INCLUDED
#define HERO_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#pragma warning( disable: 4786 )

#include <assert.h>
#include <set>

#include "abstract_script_action_ptr.h"
#include "abstract_town_ptr.h"
#include "adv_map_point.h"
#include "adventure_object_global_id.h"
#include "artifact.h"
#include "artifact_slot.h"
#include "creature_stack.h"
#include "default_heroes.h"
#include "hero_events.h"
#include "scriptable_event.h"
#include "skill.h"
#include "spell.h"
#include "spell_set.h"
#include "university_diploma.h"

class  t_abstract_town;
class  t_adventure_map;
enum   t_ai_importance;
class	t_army;
class  t_hero_carryover_data;
enum   t_hero_class;
class  t_material_array;
struct t_script_context_hero;
class  t_single_use_object;
class  t_town;
enum   t_town_type;
class  t_window;

enum t_offense_type
{
	k_offense_melee,
	k_offense_ranged,
	k_offense_spell,
	
	k_offense_type_count
};

// --------------------------------------------------------
// information about a hero
// --------------------------------------------------------
class t_hero : public t_stack_with_backpack
{
public:
	typedef t_hero_built_in_event_id		t_built_in_event_id;
	typedef t_hero_built_in_event			t_built_in_event;
	typedef t_hero_built_in_event_ptr		t_built_in_event_ptr;
	typedef t_hero_built_in_event_list		t_built_in_event_list;
	typedef t_hero_timed_event				t_timed_event;
	typedef t_hero_timed_event_ptr			t_timed_event_ptr;
	typedef t_hero_timed_event_list			t_timed_event_list;
	typedef t_hero_triggerable_event		t_triggerable_event;
	typedef t_hero_triggerable_event_ptr	t_triggerable_event_ptr;
	typedef t_hero_triggerable_event_list	t_triggerable_event_list;
	typedef t_hero_continuous_event			t_continuous_event;
	typedef t_hero_continuous_event_ptr		t_continuous_event_ptr;
	typedef t_hero_continuous_event_list	t_continuous_event_list;


	enum { k_built_in_event_count = k_hero_built_in_event_count };

	t_hero();
	t_hero( t_default_hero const& data, t_town_type alignment );
	explicit t_hero( t_hero_carryover_data const & source );
	virtual ~t_hero();

	bool						accept( t_artifact_effect_visitor& visitor ) const;
	virtual bool				add( t_artifact const& artifact, bool equip_it = true );
	void						add_book_spell( t_spell spell );
	void						add_scroll_spell( t_spell spell );
	void						add_diploma( int university_id, int id, t_skill const& skill );
	void                        add_experience( int amount, t_adventure_map const * map = NULL,
												t_player *owner = NULL, t_window* parent = 0 );
	void						add_primary_skill( std::vector<t_skill>& result, 
												   t_adventure_map const & map, bool* used ) const;
	virtual float				ai_value() const;
	virtual float				ai_value( t_creature_array const* army ) const;
	virtual float				ai_value_including_dead() const;
	int							ai_get_total_offense( t_offense_type type ) const;
	int							ai_get_total_offense() const;
	int 						ai_get_total_defense() const;
	void						ai_start_turn( t_creature_array const* army );
	virtual bool                can_add( t_creature_type creature ) const;
	virtual bool				can_add( t_creature_stack const& arg ) const;
	bool                        can_add_experience( t_player* owner ) const;
	virtual bool			    can_cast( t_spell spell ) const;
	bool                        can_learn( t_skill const& skill ) const;
	bool						can_learn( t_spell spell ) const;
	void                        check_level( t_adventure_map const & map, t_window* parent, t_player *owner );
	void						clear_nobility_town();
	t_creature_stack_ptr		clone() const;
	virtual int					compute_scouting_range() const;
	void						derandomize( t_adventure_map & map, t_player* owner );
	bool                        equip( t_artifact const& artifact );
	bool						equip( t_artifact const& artifact, t_artifact_slot slot );
	void						execute_script( t_built_in_event_id				event,
												t_script_context_hero const&	context );
	std::string                 get_accusative_pronoun() const;
	t_ai_importance				get_ai_importance() const;
	virtual t_town_type			get_alignment() const;
	virtual t_skill_mastery		get_anti_stealth_level() const;
	virtual int					get_army_move_cost( t_terrain_type terrain ) const;
	virtual int					get_army_move_bonus( bool sea_move ) const;
	virtual float				get_army_move_multiplier( bool sea_move ) const;
	virtual t_artifact const&	get_artifact( t_artifact_slot slot ) const;
	std::string					get_biography() const;
	int							get_biography_id() const;
	t_hero_class				get_class() const;
	std::string					get_class_description() const;
	std::string                 get_class_name() const;
	virtual t_model_ptr         get_combat_model( double scale ) const;
	virtual int					get_combat_movement() const;
	virtual t_hero const*		get_const_hero() const;
	virtual int					get_damage_high() const;
	int							get_damage_high( int level ) const;
	virtual int					get_damage_low() const;
	int							get_damage_low( int level ) const;
	virtual float				get_defense_basic( bool ranged ) const;
	virtual float				get_defense_bonus( bool ranged ) const;
	virtual	float				get_defense_reduction( bool ranged ) const;
	t_university_diploma const* get_diploma( int university_id ) const;
	int							get_experience() const;
	static int                  get_experience( int level );
	int							get_experience_needed_for_next_level() const;
	virtual int                 get_experience_value( int number = -1 ) const;
	virtual int					get_hit_points() const;
	int                         get_hit_points( int level ) const;
    virtual void				get_income( int day, t_material_array& income ) const;
	virtual int					get_leadership_luck_bonus() const;
	virtual int					get_leadership_morale_bonus() const;
	int							get_level() const;
	static int                  get_level( int experience );
	virtual int					get_luck() const;
	virtual int					get_magic_resistance( t_player const* owner, t_spell spell ) const;
	bool						get_max_experience_flag() const;
	virtual int			        get_maximum_spell_points() const;
	virtual t_missile_type		get_missile_type() const;
	virtual int                 get_morale( t_creature_array const& army ) const;
	virtual std::string			get_name( bool include_article = false, int number = -1 ) const;
	int							get_nobility_priority() const;
	t_abstract_town_ptr			get_nobility_town() const;
	virtual int					get_number() const;
	virtual float				get_offense( bool ranged ) const;
	virtual t_bitmap_layer_ptr	get_portrait( int height = 52, bool force_awake_portrait = false ) const;
	int							get_portrait_id() const;
	std::string                 get_possessive_pronoun() const;
	int                         get_primary_skill_count() const;
	std::vector<t_skill>		get_primary_skills() const;
	std::string                 get_pronoun() const;
	std::string                 get_reflexive_pronoun() const;
	int							get_resurrection_cost() const;
	virtual std::string			get_right_click_text() const;
	virtual int					get_shots() const;
	virtual t_skill_mastery		get_skill( t_skill_type skill ) const;
	std::vector<t_skill>        get_skill_choices( t_adventure_map const & map );
	int							get_skill_power( t_skill_type skill ) const;
	int							get_skill_power( t_skill const& skill ) const;
	std::vector<t_skill>		get_skills() const;
	virtual t_sound_ptr			get_sound( t_adv_actor_action_id action );
	virtual int					get_stoning_chance() const;
	std::vector<t_skill>		get_upgradable_skills() const;
	virtual int					get_speed() const;
	virtual int                 get_spell_cost( t_spell spell ) const;
	virtual int					get_spell_points() const;
	virtual int                 get_spell_power( t_spell spell, t_abstract_grail_data_source const & grail_data, int number = -1 ) const;
	int							get_sphinx_count() const;
	virtual t_skill_mastery		get_stealth_level() const;
	virtual int					get_tactics_defense_bonus( bool sea_battle ) const;
	virtual int					get_tactics_move_bonus( bool sea_battle ) const;
	virtual int					get_tactics_offense_bonus( bool sea_battle ) const;
	virtual int				    get_tactics_speed_bonus( bool sea_battle ) const;
	int                         get_well_recharge_level() const;
	virtual	int					get_wounds() const;
	virtual bool                has_ability( t_creature_ability ability ) const;
	bool                        has_visited( t_single_use_object const& object ) const;
	bool                        has_visited( int single_use_id ) const;
	bool						in_spellbook( t_spell spell ) const;
	virtual bool				is_active() const;
	virtual bool				is_dead() const;
	virtual bool				is_imprisoned() const;
	bool                        is_male() const;
	virtual	bool				is_native_terrain( t_terrain_type terrain ) const;
	virtual bool                knows_spell( t_spell spell ) const;
	void						learn_all_spells_cheat();
	void                        learn_skill( t_skill const& skill, bool show_dialog = false );
	virtual bool				learn_spell (t_spell spell);
	virtual void                learn_spells( t_town const* town );
	void						lower_nobility_priority();
	bool						mark_eluded( t_army const& army );
	virtual bool                preplacement( t_adventure_map& map, int pass, t_player* owner );
	virtual bool				process_continuous_events( t_adventure_map& map, t_creature_array* army, t_player* player, t_adv_map_point const* position);
	virtual void				process_new_day( t_player* owner, bool grow,
												 t_creature_array* army, int day );
	virtual bool				process_timed_events( t_adventure_map& map, t_creature_array* array, t_player* player, t_adv_map_point const* position, bool start_of_day = true);
	virtual bool				process_triggerable_events( t_adventure_map& map, std::string const& name, t_creature_array* army, t_player* player, t_adv_map_point const* position);
	void						raise_nobility_priority();
	virtual bool                read( std::streambuf& stream );
	virtual bool                read_from_map( std::streambuf& stream );
	virtual void				read_postplacement( t_adventure_map& map );
	virtual void				redistribute_artifacts( t_creature_array & army, t_artifact_list & leftovers );
	t_artifact                  remove( t_artifact_slot slot );
	void						set_built_in_events( t_built_in_event_list const & new_events );
	void						set_class( t_hero_class hero_class );
	void						set_dead( bool arg );
	void						set_imprisoned( bool arg );
	void						set_max_experience_flag();
	void						set_nobility_town( t_abstract_town *town );
	void						set_set_to_governer_flag( bool arg );
	void                        set_spell_points( int arg );
	void                        set_visited( t_single_use_object const& object, bool visited = true );
	void                        set_visited( int single_use_id, bool visited = true );
	void                        set_well_recharge_level( int arg );
	void						set_wounds( int arg );
	void						store( t_hero_carryover_data & carryover_data ) const;
	void						take_continuous_events( t_continuous_event_list & new_events );
	void						take_timed_events( t_timed_event_list & new_events );
	void						take_triggerable_events( t_triggerable_event_list & new_events );
	bool						update_class( bool show_dialog = false );
	bool						uses_spellcaster_model() const;
	bool						was_eluded( t_army const& army ) const;
	bool						was_named_by_map() const;
	virtual bool                write( std::streambuf& stream ) const;
	void						visit_town( t_abstract_town *town, t_creature_array const & owning_array );
	void						visit_sphinx();

protected:
	enum t_gender
	{
		k_gender_unknown = -1, // only used during initialization
		k_gender_female,
		k_gender_male,
	};

	t_skill			choose_skill( std::vector<t_skill> const& candidates ) const;
	void			do_summoning( t_creature_array& army );
	void			initialize();
	void			initialize( t_adventure_map& map, t_default_hero const& hero_data );
	void			update_artifact_spells();

	t_spell						m_ai_best_spell;	
	int							m_ai_best_spell_damage;
	t_ai_importance				m_ai_importance;
	t_town_type					m_alignment;
	t_artifact					m_artifacts[k_artifact_slot_hero_count];
	std::string					m_biography;
	int							m_biography_id;
	t_spell_set					m_book_spells;
	t_built_in_event_ptr		m_built_in_events[ k_built_in_event_count ];
	t_continuous_event_list		m_continuous_events;
	bool						m_dead;
	std::set<int>				m_eluded_army_ids;
	int							m_experience;
	t_gender					m_gender;
	t_hero_class				m_hero_class;
	t_artifact					m_hero_class_artifact;
	bool						m_imprisoned;
	int							m_last_combat_offer; // last time hero was offered combat as a new skill
	int							m_level;
	bool						m_max_experience;
	std::string					m_name;
	bool						m_named_by_map;
	int							m_nobility_priority; // Amount this hero really wants to be THE ruler of current nobility town. Set higher than any other hero in the town when manually selected; set to negative values when changed automatically
	t_abstract_town_ptr			m_nobility_town; // Town affected by nobility skill
	t_adventure_global_id		m_nobility_town_id; // New method of saving nobility town in save files
													// Valid ONLY between read() and read_postplacement()
	t_level_map_point_2d		m_nobility_town_position; // Old method of saving nobility town in save files
														  // Valid ONLY between read() and read_postplacement()
														  // Set to k_nobility_town_position_none if no town 
														  // Set to k_nobility_town_position_not_in_use when not between read() and read_postplacement() 
	int							m_portrait_id;
	t_spell_set					m_scroll_spells;
	t_skill_mastery				m_skills[k_skill_count];
	t_spell_set					m_spellbook;
	int							m_spell_points;
	int							m_summoning_points;
	int							m_sphinxes_visited;
	t_timed_event_list			m_timed_events;
	t_triggerable_event_list	m_triggerable_events;
	t_university_diploma_array	m_university_diplomas;
	bool						m_use_spellcaster_model;
	std::vector<int>			m_visited_objects;
	int							m_well_recharge_level; // amount of well recharging done today
	int							m_wounds;

	static t_level_map_point_2d const k_nobility_town_position_none;  // m_nobility_town_position equals this after read() if the hero is not linked to a town
	static t_level_map_point_2d const k_nobility_town_position_not_in_use; // m_nobility_town_position equals this when not between read() and read_postplacement()

private:
	bool read_ai_importance_from_map( std::streambuf & stream, int version );
	bool read_artifacts_from_map( std::streambuf & stream, int version );
	bool read_bonuses_from_map( std::streambuf & stream, int version );
	bool read_built_in_events_from_map( std::streambuf & stream, int version );
	bool read_continuous_events_from_map( std::streambuf & stream, int version );
	bool read_events( std::streambuf& stream, int version );
	bool read_gender_from_map( std::streambuf & stream );
	bool read_hero_class_from_map( std::streambuf & stream );
	bool read_level_from_map( std::streambuf & stream, int version );
	bool read_name_from_map( std::streambuf & stream, int version );
	bool read_portrait_id_from_map( std::streambuf & stream );
	bool read_spellbook_from_map( std::streambuf & stream, int version );
	bool read_timed_events_from_map( std::streambuf & stream, int version );
	bool read_triggerable_events_from_map( std::streambuf & stream, int version );
	bool write_events( std::streambuf& stream ) const;
};

// --------------------------------------------------------
// inlines for t_hero
// --------------------------------------------------------
inline void t_hero::add_book_spell( t_spell spell )
{
	m_book_spells.set( spell );
}

inline void t_hero::add_diploma( int university_id, int class_id, t_skill const& skill )
{
	m_university_diplomas[university_id].skills[class_id] = skill;
}

inline void t_hero::add_experience( int amount, t_adventure_map const * map, t_player *owner, t_window* parent )
{
	m_experience += amount;
	if ( parent != 0 && owner != 0 && map != 0 )
		check_level( *map, parent, owner);
}

inline void t_hero::add_scroll_spell( t_spell spell )
{
	m_scroll_spells.set( spell );
}

inline t_ai_importance t_hero::get_ai_importance() const
{
	return m_ai_importance;
}

inline bool t_hero::was_named_by_map() const
{
	return m_named_by_map;
}

inline t_town_type  t_hero::get_alignment() const
{
	return m_alignment;
}

inline t_artifact const& t_hero::get_artifact( t_artifact_slot slot ) const
{
	return m_artifacts[slot];
}

inline std::string t_hero::get_biography() const
{
	return m_biography;
}

inline t_hero_class t_hero::get_class() const
{
	return m_hero_class;
}

inline t_university_diploma const* t_hero::get_diploma( int university_id ) const
{
	t_university_diploma_array::const_iterator result;
	
	result = m_university_diplomas.find( university_id );
	if (result == m_university_diplomas.end())
		return 0;
	return &result->second;
}

inline int t_hero::get_experience() const
{
	return m_experience;
}

inline int          t_hero::get_level() const
{
	return m_level;
}

inline int t_hero::get_nobility_priority() const
{
	return m_nobility_priority;
}

inline t_abstract_town_ptr t_hero::get_nobility_town() const
{
	return m_nobility_town;
}

inline int t_hero::get_portrait_id() const
{
	return m_portrait_id;
}

inline int t_hero::get_biography_id() const
{
	return m_biography_id;
}

inline bool t_hero::get_max_experience_flag() const
{
	return m_max_experience;
}

inline int t_hero::get_sphinx_count() const
{
	return m_sphinxes_visited;
}

inline int t_hero::get_well_recharge_level() const
{
	return m_well_recharge_level;
}

inline bool t_hero::in_spellbook( t_spell spell ) const
{
	return m_spellbook[spell];
}

inline bool t_hero::is_imprisoned() const
{
	return m_imprisoned;
}

inline bool t_hero::is_male() const
{
	assert( m_gender != k_gender_unknown );
	return m_gender == k_gender_male;
}

inline t_artifact t_hero::remove( t_artifact_slot slot )
{
	t_artifact result = m_artifacts[slot];

	m_artifacts[slot] = t_artifact();
	update_artifact_spells();
	return result;
}

inline void t_hero::set_imprisoned( bool arg )
{
	m_imprisoned = arg;
}

inline void t_hero::set_max_experience_flag()
{
	m_max_experience = true;
}

inline void t_hero::set_spell_points( int arg )
{
	m_spell_points = arg;
}

inline void t_hero::set_well_recharge_level( int arg )
{
	m_well_recharge_level = arg;
}

inline void t_hero::set_wounds( int arg )
{
	m_wounds = arg;
}

inline bool t_hero::uses_spellcaster_model() const
{
	return m_use_spellcaster_model;
}

inline void t_hero::visit_sphinx()
{
	m_sphinxes_visited++;
}

#endif // HERO_H_INCLUDED
